import socket
from threading import Lock
from prg.proc.local_listen_thread import LocalListen
from prg.common.object_message import MessageBase


class LocalLink(MessageBase):
    def __init__(self, link_type=1, local_addr=None, link="tcp", listen=10):
        super().__init__(name="local_link")
        self.listen = listen
        self.link = link
        self.socket_collect = dict()
        self.data_queue = None
        self.local_addr = local_addr
        self.link_type = link_type
        self.socket_item = None
        self.inner_lock = Lock()
        self.link_name = 0
        self.message_thread = MessageBase(name="local_message", target=self.bind_listen)

    def create_listen(self, command):
        self.data_queue = command.command_queue
        self.start()

    def add_data(self, name, number, byte_data):
        if name not in self.socket_collect:
            if 2 == self.link_type:
                self.bind_connect(name)
            else:
                return
        self.socket_collect[name].send_data(number=number, bytes_data=byte_data)

    def get_link_name(self):
        self.inner_lock.acquire()
        self.link_name += 1
        self.inner_lock.release()
        return self.link_name

    def bind_listen(self):
        print("local address: %s" % str(self.local_addr))
        self.socket_item = socket.socket(socket.AF_INET, socket.SOCK_STREAM if "tcp" == self.link else socket.SOCK_DGRAM)
        self.socket_item.bind(self.local_addr)
        self.socket_item.listen(self.listen)
        with self.socket_item as socket_item:
            while self.is_run():
                client_socket, client_address = socket_item.accept()
                name = self.get_link_name()
                local_listen = LocalListen(name=name, data_queue=self.data_queue)
                self.socket_collect[name] = local_listen
                local_listen.run_listen(client_socket)

    def bind_connect(self, name):
        print("bind link to %s" % str(self.local_addr))
        self.socket_item = socket.socket(socket.AF_INET, socket.SOCK_STREAM if "tcp" == self.link else socket.SOCK_DGRAM)
        self.socket_item.connect(self.local_addr)
        local_listen = LocalListen(name=name, data_queue=self.data_queue)
        self.socket_collect[name] = local_listen
        local_listen.run_listen(self.socket_item)

    def entry(self):
        try:
            if 1 == self.link_type:
                self.message_thread.start()
            while self.is_run():
                pass
            self.message_thread.stop()
        except Exception as e:
            print("local link error: %s" % e)
        finally:
            print("local link status: %s" % str(self.message_thread.is_alive()))
